// FIT_6204_Gorodilov_InSegDoc.cpp : implementation of the CFIT_6204_Gorodilov_InSegDoc class
//

#include "stdafx.h"
#include "FIT_6204_Gorodilov_InSeg.h"
#include "FIT_6204_Gorodilov_InSegDoc.h"
#include "FIT_6204_Gorodilov_Collection.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CFIT_6204_Gorodilov_InSegDoc

IMPLEMENT_DYNCREATE(CFIT_6204_Gorodilov_InSegDoc, CDocument)

BEGIN_MESSAGE_MAP(CFIT_6204_Gorodilov_InSegDoc, CDocument)
END_MESSAGE_MAP()


// CFIT_6204_Gorodilov_InSegDoc construction/destruction

CFIT_6204_Gorodilov_InSegDoc::CFIT_6204_Gorodilov_InSegDoc()
: m_sScrollSize(400, 400)
, m_bIsSecondPoint(FALSE)
{

}

CFIT_6204_Gorodilov_InSegDoc::~CFIT_6204_Gorodilov_InSegDoc()
{
}

BOOL CFIT_6204_Gorodilov_InSegDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	m_aLines.RemoveAll();
	I.RemoveAll();
	m_bIsSecondPoint = FALSE;

	return TRUE;
}




// CFIT_6204_Gorodilov_InSegDoc serialization

void CFIT_6204_Gorodilov_InSegDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		CString buf; 
		buf.Format("%d %d\n", m_sScrollSize.cx, m_sScrollSize.cy);
		ar.WriteString(buf);
		buf.Format("0\n");
		ar.WriteString(buf);
		buf.Format("%d\n", m_aLines.GetCount());
		ar.WriteString(buf);
		for (int i = 0; i < m_aLines.GetCount(); i++) {
			CFIT_6204_Gorodilov_Line line = m_aLines[i];
			CFIT_6204_Gorodilov_Point p1 = line.GetLeftPoint();
			CFIT_6204_Gorodilov_Point p2 = line.GetRightPoint();
			buf.Format("%d %d %d %d\n", (int)p1.x, (int)p1.y, (int)p2.x, (int)p2.y);
			ar.WriteString(buf);
		}	
	}
	else
	{
		CString buf = GetNextLine(ar);
		int x,y;
		if (sscanf_s(buf, "%d%d",&x, &y) < 2) {
			return;
		}
		m_sScrollSize.cx = x;
		m_sScrollSize.cy = y;
		buf = GetNextLine(ar);
		int type;
		if (sscanf_s(buf, "%d",&type) < 1) {
			return;
		}
		buf = GetNextLine(ar);
		int N;
		if (sscanf_s(buf, "%d",&N) < 1) {
			return;
		}
		m_aLines.RemoveAll();
		I.RemoveAll();
		for (int i = 0; i < N; i++) {
			buf = GetNextLine(ar);
			int x1,y1,x2,y2;
			if (sscanf_s(buf, "%d%d%d%d",&x1, &y1, &x2, &y2 ) < 4) {
				return;
			}
			CFIT_6204_Gorodilov_Point p1(CPoint(x1, y1));
			CFIT_6204_Gorodilov_Point p2(CPoint(x2, y2));
			CFIT_6204_Gorodilov_Line line(p1,p2);
			m_aLines.Add(line);
		}
	}
}


// CFIT_6204_Gorodilov_InSegDoc diagnostics

#ifdef _DEBUG
void CFIT_6204_Gorodilov_InSegDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CFIT_6204_Gorodilov_InSegDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG


// CFIT_6204_Gorodilov_InSegDoc commands

INT_PTR CFIT_6204_Gorodilov_InSegDoc::AddLine(const CFIT_6204_Gorodilov_Line line)
{
	CFIT_6204_Gorodilov_Point left = ValidatePoint(line.GetLeftPoint());
	CFIT_6204_Gorodilov_Point right = ValidatePoint(line.GetRightPoint());
	
	m_aLines.Add(CFIT_6204_Gorodilov_Line(left, right));
	return GetLinesCount() - 1;
}

const CSize CFIT_6204_Gorodilov_InSegDoc::GetScrollSize(void) const
{
	return m_sScrollSize;
}


const CFIT_6204_Gorodilov_Line CFIT_6204_Gorodilov_InSegDoc::GetLine(const INT_PTR index) const {
	if (index > GetLinesCount() || index < 0) {
		return CFIT_6204_Gorodilov_Line();
	}

	return m_aLines.GetAt(index);
}

const INT_PTR CFIT_6204_Gorodilov_InSegDoc::GetLinesCount(void) const {
	return m_aLines.GetCount();
}

const CFIT_6204_Gorodilov_Line CFIT_6204_Gorodilov_InSegDoc::UpDateLine(const INT_PTR index,
	const CFIT_6204_Gorodilov_Line line) 
{
	if (index > GetLinesCount() || index < 0) {
		return CFIT_6204_Gorodilov_Line();
	}
	CFIT_6204_Gorodilov_Line result = GetLine(index);

	CFIT_6204_Gorodilov_Point left = ValidatePoint(line.GetLeftPoint());
	CFIT_6204_Gorodilov_Point right = ValidatePoint(line.GetRightPoint());
	
	m_aLines[index] = CFIT_6204_Gorodilov_Line(left, right);
	return result;
}

CFIT_6204_Gorodilov_Point CFIT_6204_Gorodilov_InSegDoc::ValidatePoint(const CFIT_6204_Gorodilov_Point &point) {
	CFIT_6204_Gorodilov_Point result;
	result.x = __max(0.0, point.x);
	result.y = __max(0.0, point.y);
	result.x = __min((double)m_sScrollSize.cx,point.x);
	result.y = __min((double)m_sScrollSize.cy,point.y);
	return result;
}

INT_PTR CFIT_6204_Gorodilov_InSegDoc::Sweep(void) {
	if (GetLinesCount() <= 0) {
		return 0;
	}

	I.RemoveAll();

	INT_PTR size = m_aLines.GetCount()*2;
	CFIT_6204_Gorodilov_Point *points = new CFIT_6204_Gorodilov_Point[m_aLines.GetCount()*2];
	INT_PTR linesCount = m_aLines.GetCount();
	for (INT_PTR index = 0; index < linesCount; index++) {
		points[index*2 + 0] = m_aLines.GetAt(index).GetLeftPoint();
		points[index*2 + 0].status = RECT_POINT_LEFT;
		points[index*2 + 1] = m_aLines.GetAt(index).GetRightPoint();
		points[index*2 + 1].status = RECT_POINT_RIGHT;
	}
	qsort(points, linesCount*2,
		sizeof(*points), comparePoints);

	CArray<CFIT_6204_Gorodilov_Line *> L;
	CFIT_6204_Gorodilov_Collection E;
	INT_PTR pos = 0;
	while (pos < size || !E.isEmpty()) {
		// select p = min(E)
		CFIT_6204_Gorodilov_Point p = points[(pos++) % size];
		if (!E.isEmpty()) {
			CFIT_6204_Gorodilov_Point p2 = E.getMin();
			if (-1 == comparePoints(&p2, &p) || pos >= size) {
				p = p2;
				pos--;
				E.pop();
			}
		}

		if (RECT_POINT_LEFT == p.status) {
			CFIT_6204_Gorodilov_Line *s = p.parent;
			CFIT_6204_Gorodilov_Line *s1 = NULL;
			CFIT_6204_Gorodilov_Line *s2 = NULL;
			double s1y = 0.0;
			double s2y = 0.0;
			for (int i = 0; i < L.GetCount(); i++) {
				CFIT_6204_Gorodilov_Line *cur = L[i];
				if (cur == s) continue;
				double y = cur->GetCrossPoint(p.x);
				if (y > p.y ) {
					if (!s1) {
						s1 = cur;
						s1y = y;
					} else {
						if (y < s1y) {
							s1 = cur;
							s1y = y;
						}
					}
				} 
				if (y < p.y){
					if (!s2) {
						s2 = cur;
						s2y = y;
					} else {
						if (y > s2y) {
							s2 = cur;
							s2y = y;
						}
					}
				}
			}
			if (s1) {
				CFIT_6204_Gorodilov_Point intersection = p;
				if (crossLines(s1,s, intersection)) {
					E.addPoint(intersection);
					I.Add(intersection);
				}
			}
			if (s2) {
				CFIT_6204_Gorodilov_Point intersection = p;
				if (crossLines(s, s2, intersection)) {
					E.addPoint(intersection);
					I.Add(intersection);
				}
			}
			L.Add(s);
		} else {
			if (RECT_POINT_RIGHT == p.status) {
				CFIT_6204_Gorodilov_Line *s = p.parent;
				CFIT_6204_Gorodilov_Line *s1 = NULL;
				CFIT_6204_Gorodilov_Line *s2 = NULL;
				double s1y = 0.0;
				double s2y = 0.0;
				for (int i = 0; i < L.GetCount(); i++) {
					CFIT_6204_Gorodilov_Line *cur = L[i];
					if (cur == s) continue;
					double y = cur->GetCrossPoint(p.x);
					if (y > p.y ) {
						if (!s1) {
							s1 = cur;
							s1y = y;
						} else {
							if (y < s1y) {
								s1 = cur;
								s1y = y;
							}
						}
					} 
					if (y < p.y) {
						if (!s2) {
							s2 = cur;
							s2y = y;
						} else {
							if (y > s2y) {
								s2 = cur;
								s2y = y;
							}
						}
					}
				}
				if (s1 && s2) {
					CFIT_6204_Gorodilov_Point intersection = p;
					if (crossLines(s1,s2, intersection)) {
						if (intersection.x >= p.x) {
							E.addPoint(intersection);
							I.Add(intersection);
						}
					}
				}
				for (int i = 0; i < L.GetCount(); i++) {
					if (L[i] == s) {
						L.RemoveAt(i);
						break;
					}
				}
			} else { // INTERSECTION
				CFIT_6204_Gorodilov_Line *s1 = p.parent;
				CFIT_6204_Gorodilov_Line *s2 = p.parent2;
				CFIT_6204_Gorodilov_Line *s3 = NULL;
				CFIT_6204_Gorodilov_Line *s4 = NULL;
				double s3y = 0.0;
				double s4y = 0.0;
				for (int i = 0; i < L.GetCount(); i++) {
					CFIT_6204_Gorodilov_Line *cur = L[i];
					if (cur == s1) continue;
					if (cur == s2) continue;
					double y = cur->GetCrossPoint(p.x);
					if (y > p.y ) {
						if (!s3) {
							s3 = cur;
							s3y = y;
						} else {
							if (y < s3y) {
								s3 = cur;
								s3y = y;
							}
						}
					} 
					if (y < p.y) {
						if (!s4) {
							s4 = cur;
							s4y = y;
						} else {
							if (y > s4y) {
								s4 = cur;
								s4y = y;
							}
						}
					}
				}
				if (s3) {
					CFIT_6204_Gorodilov_Point intersection = p;
					if (crossLines(s3,s2, intersection)) {
						E.addPoint(intersection);
						I.Add(intersection);
					}
				}
				if (s4) {
					CFIT_6204_Gorodilov_Point intersection = p;
					if (crossLines(s1, s4, intersection)) {
						E.addPoint(intersection);
						I.Add(intersection);
					}
				}
			}
		}
	}

	delete []points;
	return 0;
}
CString GetNextLine(CArchive &ar) {
	CString line = "";
	BOOL isRead = true;
	BOOL isSpace = true;
	while (isSpace && isRead) {
		isSpace = false;
		isRead = ar.ReadString(line);
		line.Trim(" \n\t");
		if (line.IsEmpty()) {
			isSpace = true;
		}
		if (line.GetLength() > 2)
			if ((line[0] == '/') &&
				(line[1] == '/')) {
				isSpace = true;
			}
	}
	return line;
}
